1 using System;
2 using UnityEngine;
3
4 namespace UnityStandardAssets.ImageEffects
5 {
6 [ExecuteInEditMode]
7 [AddComponentMenu ("Image Effects/Color Adjustments/Color Correction (3D Lookup Texture)")]
8 public class ColorCorrectionLookup : PostEffectsBase
9 {
10 public Shader shader;
11 private Material material;
12
13 // serialize this instead of having another 2d texture ref'ed
14 public Texture3D converted3DLut = null;
15 public string basedOnTempTex = "";
16
17
18 public override bool CheckResources () {
19 CheckSupport (false);
20
21 material = CheckShaderAndCreateMaterial (shader, material);
22
23 if (!isSupported || !SystemInfo.supports3DTextures)
24 ReportAutoDisable ();
25 return isSupported;
26 }
27
28 void OnDisable () {
29 if (material) {
30 DestroyImmediate (material);
31 material = null;
32 }
33 }
34
35 void OnDestroy () {
36 if (converted3DLut)
37 DestroyImmediate (converted3DLut);
38 converted3DLut = null;
39 }
40
41 public void SetIdentityLut () {
42 int dim = 16;
43 var newC = new Color[dim*dim*dim];
44 float oneOverDim = 1.0f / (1.0f * dim - 1.0f);
45
46 for(int i = 0; i < dim; i++) {
47 for(int j = 0; j < dim; j++) {
48 for(int k = 0; k < dim; k++) {
49 newC[i + (j*dim) + (k*dim*dim)] = new Color((i*1.0f)*oneOverDim, (j*1.0f)*oneOverDim, (k*1.0f)*oneOverDim, 1.0f);
50 }
51 }
52 }
53
54 if (converted3DLut)
55 DestroyImmediate (converted3DLut);
56 converted3DLut = new Texture3D (dim, dim, dim, TextureFormat.ARGB32, false);
57 converted3DLut.SetPixels (newC);
58 converted3DLut.Apply ();
59 basedOnTempTex = "";
60 }
61
62 public bool ValidDimensions ( Texture2D tex2d) {
63 if (!tex2d) return false;
64 int h = tex2d.height;
65 if (h != Mathf.FloorToInt(Mathf.Sqrt(tex2d.width))) {
66 return false;
67 }
68 return true;
69 }
70
71 public void Convert ( Texture2D temp2DTex, string path) {
72
73 // conversion fun: the given 2D texture needs to be of the format
74 // w * h, wheras h is the 'depth' (or 3d dimension 'dim') and w = dim * dim
75
76 if (temp2DTex) {
77 int dim = temp2DTex.width * temp2DTex.height;
78 dim = temp2DTex.height;
79
80 if (!ValidDimensions(temp2DTex)) {
81 Debug.LogWarning ("The given 2D texture " + temp2DTex.name + " cannot be used as a 3D LUT.");
82 basedOnTempTex = "";
83 return;
84 }
85
86 var c = temp2DTex.GetPixels();
87 var newC = new Color[c.Length];
88
89 for(int i = 0; i < dim; i++) {
90 for(int j = 0; j < dim; j++) {
91 for(int k = 0; k < dim; k++) {
92 int j_ = dim-j-1;
93 newC[i + (j*dim) + (k*dim*dim)] = c[k*dim+i+j_*dim*dim];
94 }
95 }
96 }
97
98 if (converted3DLut)
99 DestroyImmediate (converted3DLut);
100 converted3DLut = new Texture3D (dim, dim, dim, TextureFormat.ARGB32, false);
101 converted3DLut.SetPixels (newC);
102 converted3DLut.Apply ();
103 basedOnTempTex = path;
104 }
105 else {
106 // error, something went terribly wrong
107 Debug.LogError ("Couldn't color correct with 3D LUT texture. Image Effect will be disabled.");
108 }
109 }
110
111 void OnRenderImage (RenderTexture source, RenderTexture destination) {
112 if (CheckResources () == false || !SystemInfo.supports3DTextures) {
113 Graphics.Blit (source, destination);
114 return;
115 }
116
117 if (converted3DLut == null) {
118 SetIdentityLut ();
119 }
120
121 int lutSize = converted3DLut.width;
122 converted3DLut.wrapMode = TextureWrapMode.Clamp;
123 material.SetFloat("_Scale", (lutSize - 1) / (1.0f*lutSize));
124 material.SetFloat("_Offset", 1.0f / (2.0f * lutSize));
125 material.SetTexture("_ClutTex", converted3DLut);
126
127 Graphics.Blit (source, destination, material, QualitySettings.activeColorSpace == ColorSpace.Linear ? 1 : 0);
128 }
129 }
130 }